1 Introduction

1.1 Biological background and motivation

Immune molecules such as B and T cell receptors, human leukocyte antigens (HLAs) or killer Ig-like receptors (KIRs) are encoded in the genetically most diverse loci of the human genome. Many of these immune genes are hyperpolymorphic, showing high allelic diversity across human populations. In addition, typical immune molecules are polygenic, which means that multiple functionally similar genes encode the same protein subunit.

We have developed a workflow, that allows quantification of expression and interactive exploration of donor-specific alleles of different immune genes. The workflow is composed of three steps: 1. typing of donor-specific alleles, 2. quantification of these alleles in single-cell transcriptomic data, 3. exploration of single-cell transcriptomic data using SingleCellAlleleExperiment (SCAE) class.

The software for steps 1 and 2 is currently not yet publicly available. The present repository is dedicated to the implementation of the SingleCellAlleleExperiment (SCAE) class. The aim of the here presented class is to provide an addition to the SingleCellExperiment (SCE) object that can simultaneously contain quantification of alleles, genes, and groups of functionally similar genes and thus allows data analysis across these immunologically relevant different layers of annotation.

1.2 The SingleCellAlleleExperiment (SCAE) class

The SingleCellAlleleExperiment (SCAE) class is a container for storing and handling allele-aware quantification data for immune genes. The SCAE class is derived from the SingleCellExperiment (SCE) class and uses the same overall object architecture. However, multiple data layers are integrated into the object during object generation. During object generation, the allele information is aggregated into two additional data layers via an ontology based design principle and appended to the initial raw data using a lookup table. Thus the final SCAE object contains quantification of all classical genes (“non-immune genes”) and additionally a multi-layer representation of a set of genes of interest (e.g. “immune genes” such as HLAs, Igs, KIRs). For these genes of interest, the quantification is stored on the levels of alleles, genes, and functionally similar groups of genes (refer to Figure 1).

For example, the counts of the alleles A*01:01:01:01 and A*02:01:01:01 that are present in the raw input data will be combined into the HLA-A immune gene layer. Next, all counts for the present HLA-class I immune genes will be combined into the HLA-class I functional class layer. The information necessary to perform these transformations is saved in a lookup table retrieved from the IPD-IMGT/HLA database and other immunogenetic databases.

The implemented object follows similar conventions like the SCE class, where rows should represent features (genes, transcripts) and columns should represent cells. Established single cell packages like scater and scran can be used with the newly implemented SCAE object to perform downstream analysis on immune gene expression. This allows data exploration on functional as well as allele level.

alt text here Figure 1: Scheme of SingleCellAlleleExperiment object structure with lookup table.

1.3 Expected input

The read in function of the SCAE package readAlleleCounts() expects specific files and file identifiers. The stated input directory should contain the following files:

  • cells_x_genes.barcodes.txt (list of barcodes/cell identifiers)
  • cells_x_genes.features.txt (list of feature identifiers)
  • cells_x_genes.mtx (Contains the quantification matrix)
  • lookup_table.csv (Info for generating multiple data layers)

These identifiers are set as standard values, but can be changed in the corresponding parameters of the readAlleleCounts() function in case they are different.

The used dataset for later downstream analysis and testing of the functionalities of the multi-layer object is a dual-center, two-cohort study where whole blood and peripheral blood mononuclear cells underwent scRNA-sequencing. The whole transcriptome dataset is under controlled access and not for public use. The corresponding publication Severe COVID-19 Is Marked by a Dysregulated Myeloid Cell Compartment can be found here.

2 Loading packages

The following packages are abundant for performing the downstream analysis and visualization.

library(SingleCellAlleleExperiment)
library(scran)
library(scater)
library(tidyverse)
library(patchwork)
library(ggplot2)

3 Reading in data and quality check

3.1 Stating input directory containing the expected files

First the directory path is stated. The directory should contain all expected files.

dir_path <- system.file("extdata", package = "SingleCellAlleleExperiment")
list.files(dir_path)
## [1] "cells_x_genes.barcodes.txt" "cells_x_genes.genes.txt"   
## [3] "cells_x_genes.mtx"          "lookup_table_HLA_only.csv" 
## [5] "scae_advanced.png"

3.2 Generate SingleCellAlleleExperiment object

SCAE objects implements the same object architecture as SCE objects. When reading allele counts, the method by default filters cells from a knee-plot inflection point. Alternatively, manual filter settings can be provided.

The filter parameter of the readAlleleCounts function gives multiple options on how to perform filtering on the cells. The valid parameter options are given as filter = c("yes", "no", "custom"). Setting filter = "yes" automatically filters the cells on the inflection point that is computed on a knee plot. filter = "no" only shows the knee plot without generating a full SCAE object. This mode could be used prior to using filter = "custom", where the user can give a custom threshold for manually filtering out cells in the filter_threshold parameter.

Additionally the verbose parameter gives an option to toggle runtime-information for the different steps during object generation, which is printed to the console. Messages regarding the filtering process (inflection point threshold) won’t be toggled off if verbose = FALSE.

The three different modes for filtering and creating a SCAE object are shown in the following code-chunks:


Only show the knee plot without generating a SCAE object. All function parameters are shown. Information messages (verbose = FALSE) are turned off.

scae <- readAlleleCounts(dir_path,
                         sample_names = "example_data",
                         filter = "no",
                         symbols = "orgdb",
                         exp_type = "WTA",
                         lookup_file = "lookup_table_HLA_only.csv",
                         barcode_file = "cells_x_genes.barcodes.txt",
                         gene_file = "cells_x_genes.genes.txt",
                         matrix_file = "cells_x_genes.mtx",
                         tag_feature_mtx = "cells_x_genes.genes.txt",
                         tag_feature_barcodes = "cells_x_genes.barcodes.txt",
                         filter_threshold = NULL,
                         verbose = FALSE)

## Suggested threshold based on inflection point is at:  105  UMI counts.


Read in and automatic filtering mode, generating a SCAE object. Filtering performed on the computed inflection point on the knee plot.

scae <- readAlleleCounts(dir_path,
                         sample_names = "example_data",
                         filter = "yes",
                         symbols = "orgdb",
                         exp_type = "WTA",
                         verbose = TRUE)
## Filtering performed based on the inflection point at:  105  UMI counts.
## Runtime check (1/2) Read_in: 2 seconds
##      Generating SCAE (1/5) extending rowData: 2.23 seconds
##      Generating SCAE (2/5) filtering and normalization: 0.13 seconds
##      Generating SCAE (3/5) alleles2genes: 1.55 seconds
##      Generating SCAE (4/5) genes2functional: 1.58 seconds
##      Generating SCAE (5/5) log_transform: 1.58 seconds
## Runtime check (2/2) Generating SCAE completed: 5.85 seconds
## Total runtime, completed read_in, filtering and normalization and generating scae object 8 seconds

scae
## class: SingleCellAlleleExperiment 
## dim: 62718 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(62718): ENSG00000160072.20 ENSG00000279928.2 ... HLA_class_I
##   HLA_class_II
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):


Read in and custom filtering mode, generating a SCAE object. Filtering performed on the threshold stated in the filter_threshold parameter.

#this is the object used in the further workflow
scae <- readAlleleCounts(dir_path,
                         sample_names = "example_data",
                         filter = "custom",
                         symbols = "orgdb",
                         exp_type = "WTA",
                         filter_threshold = 105,
                         verbose = FALSE)
scae
## class: SingleCellAlleleExperiment 
## dim: 62718 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(62718): ENSG00000160072.20 ENSG00000279928.2 ... HLA_class_I
##   HLA_class_II
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):

3.2.1 RowData slot

Two new classification columns are introduced in the rowData slot. Namely the NI_I column and Quant_type column. Both columns are used to identify each row of the object to its corresponding data layer (see figure 1).

rowData(scae)
## DataFrame with 62718 rows and 4 columns
##                            Ensembl_ID       Symbol        NI_I  Quant_type
##                           <character>  <character> <character> <character>
## ENSG00000160072.20 ENSG00000160072.20       ATAD3B          NI           G
## ENSG00000279928.2   ENSG00000279928.2           NA          NI           G
## ENSG00000228037.1   ENSG00000228037.1 LOC100996583          NI           G
## ENSG00000142611.17 ENSG00000142611.17       PRDM16          NI           G
## ENSG00000284616.1   ENSG00000284616.1           NA          NI           G
## ...                               ...          ...         ...         ...
## HLA-DQA1                     HLA-DQA1     HLA-DQA1           I           G
## HLA-DQB1                     HLA-DQB1     HLA-DQB1           I           G
## HLA-DPB1                     HLA-DPB1     HLA-DPB1           I           G
## HLA_class_I               HLA_class_I  HLA_class_I           I           F
## HLA_class_II             HLA_class_II HLA_class_II           I           F

3.2.2 ColData slot

As the object extends the count matrix during the object generation, its abundant to compute scaling factors on the raw data prior to extending and integrating the data layers. The scaling factors are used for scaling normalization in a later step of the SCAE constructor.

colData(scae)
## DataFrame with 7501 rows and 3 columns
##                                   Sample                Barcode sizeFactor
##                              <character>            <character>  <numeric>
## ATACTTAGGACAGTGGTAGGCTACAGA example_data ATACTTAGGACAGTGGTAGG..   3.491050
## CAGAATCGTGAGTGCGAAGGTGAGTTA example_data CAGAATCGTGAGTGCGAAGG..   0.493435
## AGCCATCACACCTGAGTCCAATACAAG example_data AGCCATCACACCTGAGTCCA..   2.328737
## CTTCACATAGTGCAGTAATACTTCGGA example_data CTTCACATAGTGCAGTAATA..   2.316401
## ATGTAATGGCCGTATCTAACTGAATTC example_data ATGTAATGGCCGTATCTAAC..   0.190521
## ...                                  ...                    ...        ...
## GCAATCCGATGTGAAGAAAGCTATGTG example_data GCAATCCGATGTGAAGAAAG..   0.581156
## GAGCCAATAAGCGACACCAACGTGTGA example_data GAGCCAATAAGCGACACCAA..   1.894241
## CACACACTAATCCTAGGACAAACGTGG example_data CACACACTAATCCTAGGACA..   2.538447
## ACACACAAATTGCGTACATTCAGCTCA example_data ACACACAAATTGCGTACATT..   0.150772
## ATCAGAGCTGTACATCTACACGATCCG example_data ATCAGAGCTGTACATCTACA..   0.149401

3.2.3 Extract information from the different data layers

Additionally to the established getters from the SCE package, new getters are implemented to retrieve the different data layers integrated in the SCAE object.


3.2.3.1 Non-immune genes

get_nigenes(scae)
## class: SingleCellAlleleExperiment 
## dim: 62695 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(62695): ENSG00000160072.20 ENSG00000279928.2 ...
##   ENSG00000277475.1 ENSG00000275405.1
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
head(rownames(get_nigenes(scae)))
## [1] "ENSG00000160072.20" "ENSG00000279928.2"  "ENSG00000228037.1" 
## [4] "ENSG00000142611.17" "ENSG00000284616.1"  "ENSG00000157911.11"


3.2.3.2 Alleles

get_alleles(scae)
## class: SingleCellAlleleExperiment 
## dim: 14 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(14): A*02:01:01:01 A*26:01:01:01 ... DPB1*10:01:01:01
##   DPB1*13:01:01:01
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
head(rownames(get_alleles(scae)))
## [1] "A*02:01:01:01" "A*26:01:01:01" "B*51:01:01:01" "B*57:01:01:01"
## [5] "C*04:01:01:01" "C*06:02:01:01"


3.2.3.3 Immune genes

get_agenes(scae)
## class: SingleCellAlleleExperiment 
## dim: 7 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(7): HLA-A HLA-B ... HLA-DQB1 HLA-DPB1
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
head(rownames(get_agenes(scae)))
## [1] "HLA-A"    "HLA-B"    "HLA-C"    "HLA-DRB1" "HLA-DQA1" "HLA-DQB1"


3.2.3.4 Functional class

get_func(scae)
## class: SingleCellAlleleExperiment 
## dim: 2 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(2): HLA_class_I HLA_class_II
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
head(rownames(get_func(scae)))
## [1] "HLA_class_I"  "HLA_class_II"



4 Expression evaluation

Checking the expression for the allele-layer, immune gene layer and functional class layer. Allele identifiers are in the form of A*02:01:01:01. The immune genes are in the form of HLA-A and the functional classes HLA_class_I. Here we see that HLA_class_I and HLA-C are the most abundant functional class and immune gene respectively, given the underlying dataset.

all_alleles <- c(rownames(get_alleles(scae)),
                 rownames(get_agenes(scae)),
                 rownames(get_func(scae)))

plotExpression(scae, all_alleles)


5 Downstream analysis

In the following sections, main steps for dimensional reduction are performed, offering insights into the different data layers of the SCAE object as well giving an idea on how to perform immune gene expression analysis.

5.1 Subsetting the different layers

The non-imune genes are combined with each of the integrated immune gene allele-aware layers to determine three different subsets.

5.1.1 Non-immune genes + alleles

scae_ni_a <- scae[c(rownames(get_nigenes(scae)), rownames(get_alleles(scae))), ]

scae_ni_a
## class: SingleCellAlleleExperiment 
## dim: 62709 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(62709): ENSG00000160072.20 ENSG00000279928.2 ...
##   DPB1*10:01:01:01 DPB1*13:01:01:01
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):


5.1.2 Non-immune genes + immune genes

scae_ni_g <- scae[c(rownames(get_nigenes(scae)), rownames(get_agenes(scae))), ]

scae_ni_g
## class: SingleCellAlleleExperiment 
## dim: 62702 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(62702): ENSG00000160072.20 ENSG00000279928.2 ... HLA-DQB1
##   HLA-DPB1
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):


5.1.3 Non-immune genes + functional class

scae_ni_f <- scae[c(rownames(get_nigenes(scae)), rownames(get_func(scae))), ]

scae_ni_f
## class: SingleCellAlleleExperiment 
## dim: 62697 7501 
## metadata(0):
## assays(2): counts logcounts
## rownames(62697): ENSG00000160072.20 ENSG00000279928.2 ... HLA_class_I
##   HLA_class_II
## rowData names(4): Ensembl_ID Symbol NI_I Quant_type
## colnames(7501): ATACTTAGGACAGTGGTAGGCTACAGA CAGAATCGTGAGTGCGAAGGTGAGTTA
##   ... ACACACAAATTGCGTACATTCAGCTCA ATCAGAGCTGTACATCTACACGATCCG
## colData names(3): Sample Barcode sizeFactor
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):

5.2 Dimensional Reduction

5.2.1 Model variance and HVGs for all data layers

Using the modelGeneVar() function prior to getTopHVGs. Both functions are part from the scran package. Compute a list of HVGs for each data layer. Return the top 0.1 % HVGs per layer using getTopHVGs.

df_ni_a <- modelGeneVar(scae_ni_a)
top_ni_a <- getTopHVGs(df_ni_a, prop = 0.1)
df_ni_g <- modelGeneVar(scae_ni_g)
top_ni_g <- getTopHVGs(df_ni_g, prop = 0.1)
df_ni_f <- modelGeneVar(scae_ni_f)
top_ni_f <- getTopHVGs(df_ni_f, prop = 0.1)

5.2.2 PCA

Compute PCA for each layer and store the results in the object. Its Important to make unique identifiers for each layer/run or the results will be overwritten and just saved as PCA. Here, the runPCA functions from the scater package is used.

set.seed(18)
scae <- runPCA(scae, ncomponents = 10, subset_row = top_ni_a, exprs_values = "logcounts", name = "PCA_a")
scae <- runPCA(scae, ncomponents = 10, subset_row = top_ni_g, exprs_values = "logcounts", name = "PCA_g")
scae <- runPCA(scae, ncomponents = 10, subset_row = top_ni_f, exprs_values = "logcounts", name = "PCA_f")
reducedDimNames(scae)
## [1] "PCA_a" "PCA_g" "PCA_f"

5.2.3 t-SNE

The same goes for running t-SNE with the runTSNE function from the scater package. Unique identifiers are stated here for each layer as well.

set.seed(18)
scae <- runTSNE(scae, dimred= "PCA_a",  name = "TSNE_a")
set.seed(18)
scae <- runTSNE(scae, dimred= "PCA_g",  name = "TSNE_g")
set.seed(18)
scae <- runTSNE(scae, dimred= "PCA_f",  name = "TSNE_f")

List of results from the performed reduced dimension analysis.

reducedDimNames(scae)
## [1] "PCA_a"  "PCA_g"  "PCA_f"  "TSNE_a" "TSNE_g" "TSNE_f"

5.3 Visualization

Exemplary visualization for the t-SNE results on gene level for immune genes that relate to HLA-class I. In the given dataset, these are the immune genes HLA-A, HLA-B and HLA-C plotted alongside their alleles. This allows for insights into potential genetic differences shown on allele-level.

5.3.1 HLA-A immune gene and alleles

which_tsne <- "TSNE_g"

#EGA_hla_a_alleles
tsne_g_a  <- plotReducedDim(scae, dimred = which_tsne, colour_by = "HLA-A") + ggtitle("HLA-A gene")
tsne_g_a1 <- plotReducedDim(scae, dimred = which_tsne, colour_by = "A*02:01:01:01") + ggtitle("Allele A*02:01:01:01")
tsne_g_a2 <- plotReducedDim(scae, dimred = which_tsne, colour_by = "A*26:01:01:01") + ggtitle("Allele A*26:01:01:01")

p2 <- tsne_g_a + tsne_g_a1 + tsne_g_a2

p2

5.3.2 HLA-B immune gene and alleles

tsne_g_b  <- plotReducedDim(scae, dimred = which_tsne, colour_by = "HLA-B") + ggtitle("HLA-B gene")
tsne_g_b1 <- plotReducedDim(scae, dimred = which_tsne, colour_by = "B*51:01:01:01") + ggtitle("Allele B*51:01:01:01")
tsne_g_b2 <- plotReducedDim(scae, dimred = which_tsne, colour_by = "B*57:01:01:01") + ggtitle("Allele B*57:01:01:01")

p3 <- tsne_g_b  + tsne_g_b1 + tsne_g_b2

p3

5.3.3 HLA-C immune gene and alleles

#EGA_hla_c_alleles 
tsne_g_g  <- plotReducedDim(scae, dimred = which_tsne, colour_by = "HLA-C") + ggtitle("HLA-C gene")
tsne_g_c1 <- plotReducedDim(scae, dimred = which_tsne, colour_by = "C*04:01:01:01") + ggtitle("Allele C*04:01:01:01")
tsne_g_c2 <- plotReducedDim(scae, dimred = which_tsne, colour_by = "C*06:02:01:01") + ggtitle("Allele C*06:02:01:01")

p1 <- tsne_g_g  + tsne_g_c1 + tsne_g_c2 

p1


6 Additional

As the SCAE object is extending the SCE object, it is also compatible with the iSEE package for interactive data exploration.

7 Session Information

sessionInfo()
## R version 4.1.2 (2021-11-01)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 22.04.3 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=de_DE.UTF-8        LC_COLLATE=C              
##  [5] LC_MONETARY=de_DE.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=de_DE.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats4    stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] patchwork_1.1.3                       lubridate_1.9.2                      
##  [3] forcats_1.0.0                         stringr_1.5.0                        
##  [5] dplyr_1.1.2                           purrr_1.0.2                          
##  [7] readr_2.1.4                           tidyr_1.3.0                          
##  [9] tibble_3.2.1                          tidyverse_2.0.0                      
## [11] scater_1.22.0                         ggplot2_3.4.3                        
## [13] scran_1.22.1                          scuttle_1.4.0                        
## [15] SingleCellAlleleExperiment_0.0.0.9000 SingleCellExperiment_1.16.0          
## [17] SummarizedExperiment_1.24.0           Biobase_2.54.0                       
## [19] GenomicRanges_1.46.1                  GenomeInfoDb_1.30.1                  
## [21] IRanges_2.28.0                        S4Vectors_0.32.4                     
## [23] BiocGenerics_0.40.0                   MatrixGenerics_1.6.0                 
## [25] matrixStats_1.0.0                     BiocStyle_2.22.0                     
## 
## loaded via a namespace (and not attached):
##   [1] Rtsne_0.16                ggbeeswarm_0.7.2         
##   [3] colorspace_2.1-0          bluster_1.4.0            
##   [5] XVector_0.34.0            BiocNeighbors_1.12.0     
##   [7] rstudioapi_0.15.0         farver_2.1.1             
##   [9] ggrepel_0.9.3             bit64_4.0.5              
##  [11] AnnotationDbi_1.56.2      fansi_1.0.4              
##  [13] xml2_1.3.5                R.methodsS3_1.8.2        
##  [15] sparseMatrixStats_1.6.0   cachem_1.0.8             
##  [17] knitr_1.43                jsonlite_1.8.7           
##  [19] cluster_2.1.4             dbplyr_2.3.3             
##  [21] R.oo_1.25.0               png_0.1-8                
##  [23] HDF5Array_1.22.1          BiocManager_1.30.22      
##  [25] compiler_4.1.2            httr_1.4.6               
##  [27] dqrng_0.3.0               Matrix_1.6-1             
##  [29] fastmap_1.1.1             limma_3.50.3             
##  [31] cli_3.6.1                 BiocSingular_1.10.0      
##  [33] htmltools_0.5.6           prettyunits_1.1.1        
##  [35] tools_4.1.2               rsvd_1.0.5               
##  [37] igraph_1.5.1              gtable_0.3.3             
##  [39] glue_1.6.2                GenomeInfoDbData_1.2.7   
##  [41] rappdirs_0.3.3            Rcpp_1.0.11              
##  [43] jquerylib_0.1.4           rhdf5filters_1.6.0       
##  [45] vctrs_0.6.3               Biostrings_2.62.0        
##  [47] DelayedMatrixStats_1.16.0 xfun_0.40                
##  [49] beachmat_2.10.0           timechange_0.2.0         
##  [51] lifecycle_1.0.3           irlba_2.3.5.1            
##  [53] statmod_1.5.0             XML_3.99-0.14            
##  [55] org.Hs.eg.db_3.14.0       edgeR_3.36.0             
##  [57] zlibbioc_1.40.0           scales_1.2.1             
##  [59] hms_1.1.3                 parallel_4.1.2           
##  [61] rhdf5_2.38.1              yaml_2.3.7               
##  [63] curl_5.0.2                memoise_2.0.1            
##  [65] gridExtra_2.3             sass_0.4.7               
##  [67] biomaRt_2.50.3            stringi_1.7.12           
##  [69] RSQLite_2.3.1             highr_0.10               
##  [71] ScaledMatrix_1.2.0        filelock_1.0.2           
##  [73] BiocParallel_1.28.3       rlang_1.1.1              
##  [75] pkgconfig_2.0.3           bitops_1.0-7             
##  [77] evaluate_0.21             lattice_0.21-8           
##  [79] Rhdf5lib_1.16.0           labeling_0.4.2           
##  [81] cowplot_1.1.1             bit_4.0.5                
##  [83] tidyselect_1.2.0          magrittr_2.0.3           
##  [85] bookdown_0.35             R6_2.5.1                 
##  [87] generics_0.1.3            metapod_1.2.0            
##  [89] DelayedArray_0.20.0       DBI_1.1.3                
##  [91] pillar_1.9.0              withr_2.5.0              
##  [93] KEGGREST_1.34.0           RCurl_1.98-1.12          
##  [95] crayon_1.5.2              DropletUtils_1.14.2      
##  [97] utf8_1.2.3                BiocFileCache_2.2.1      
##  [99] tzdb_0.4.0                rmarkdown_2.24           
## [101] viridis_0.6.4             progress_1.2.2           
## [103] locfit_1.5-9.8            grid_4.1.2               
## [105] blob_1.2.4                digest_0.6.33            
## [107] R.utils_2.12.2            munsell_0.5.0            
## [109] beeswarm_0.4.0            viridisLite_0.4.2        
## [111] vipor_0.4.5               bslib_0.5.1